package io.kiki.sba.registry.common.model.slot;


import lombok.Getter;

import java.io.Serializable;
import java.util.*;

/**
 * DataNodeAndLeaderFollowerSlotIdSet
 */

public final class DataStoreNode implements Serializable {
    private static final long serialVersionUID = 1L;
    @Getter
    private final String dataStoreNodeId;
    private final Set<Integer> leaderSlotIdSet = new TreeSet<>();
    private final Set<Integer> followerSlotIdSet = new TreeSet<>();


    public DataStoreNode(String dataStoreNodeId) {
        this.dataStoreNodeId = dataStoreNodeId;
    }

    public static List<String> collectDataStoreNodeIdList(Collection<DataStoreNode> collection) {
        Set<String> set = new LinkedHashSet<>();
        collection.forEach(dataNodeAndSlot -> set.add(dataNodeAndSlot.dataStoreNodeId));
        return new ArrayList<>(set);
    }

    /**
     * Fork data node slot.
     *
     * @param ignoreFollowers the ignore followers
     * @return the data node slot
     */
    public DataStoreNode fork(boolean ignoreFollowers) {
        DataStoreNode dataStoreNode = new DataStoreNode(dataStoreNodeId);
        dataStoreNode.leaderSlotIdSet.addAll(leaderSlotIdSet);
        if (!ignoreFollowers) {
            dataStoreNode.followerSlotIdSet.addAll(followerSlotIdSet);
        }
        return dataStoreNode;
    }

    public DataStoreNode addLeaderSlotId(int leaderSlotId) {
        leaderSlotIdSet.add(leaderSlotId);
        return this;
    }

    public DataStoreNode addLeaderSlotId(Collection<Integer> leaderSlotIdSet) {
        this.leaderSlotIdSet.addAll(leaderSlotIdSet);
        return this;
    }

    public DataStoreNode removeLeaderSlotId(int leaderSlotId) {
        leaderSlotIdSet.remove(leaderSlotId);
        return this;
    }

    public DataStoreNode addFollowerSlotId(int followerSlotId) {
        followerSlotIdSet.add(followerSlotId);
        return this;
    }

    public DataStoreNode addFollowerSlotId(Collection<Integer> followerSlotIdSet) {
        this.followerSlotIdSet.addAll(followerSlotIdSet);
        return this;
    }

    public DataStoreNode removeFollowerSlotId(int followerSlotId) {
        followerSlotIdSet.remove(followerSlotId);
        return this;
    }

    public boolean containsLeaderSlotId(int leaderSlotId) {
        return leaderSlotIdSet.contains(leaderSlotId);
    }

    public boolean containsFollowerSlotId(int followerSlotId) {
        return followerSlotIdSet.contains(followerSlotId);
    }


    public Set<Integer> getLeaderSlotIdSet() {
        return Collections.unmodifiableSet(leaderSlotIdSet);
    }

    public Set<Integer> getFollowerSlotIdSet() {
        return Collections.unmodifiableSet(followerSlotIdSet);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        DataStoreNode that = (DataStoreNode) o;
        return Objects.equals(dataStoreNodeId, that.dataStoreNodeId) && Objects.equals(leaderSlotIdSet, that.leaderSlotIdSet) && Objects.equals(followerSlotIdSet, that.followerSlotIdSet);
    }

    @Override
    public int hashCode() {
        return Objects.hash(dataStoreNodeId, leaderSlotIdSet, followerSlotIdSet);
    }


}
